package ar.edu.itba.it.poo.dd.backend
import scala.collection.mutable.MutableList

sealed abstract class Direction(val x: Int, val y: Int)
case object Up extends Direction(0, -1)
case object Down extends Direction(0, 1)
case object Left extends Direction(-1, 0)
case object Right extends Direction(1, 0)

class Board(val name: String, val cells: Array[Array[Tile]], val player: Player, val listener: BoardListener) {
  newVisibleTiles foreach {_.visible = true }
  val rows = cells.size
  val columns = cells(0).size
  def apply(row: Int)(column: Int) = cells(row)(column)
  private def isPositionValid(row: Int, column: Int) = cells.isDefinedAt(row) && cells(0).isDefinedAt(column)
  private def neighboor(direction: Direction) = this(player.row + direction.y)(player.column + direction.x)

  def movePlayer(direction: Direction) {
    val nextCell = neighboor(direction)
    if (nextCell.canEnter(player)) {
      nextCell.onPlayerEnter(player)
      player.move(direction)
    }
    
    revealTiles
  }

  def at(row: Int, column: Int) = {
    checkPosition(row, column)
    cells(row)(column)
  }

  def checkPosition(row: Int, column: Int) = if (!isPositionValid(row, column)) throw new RuntimeException("Illegal position (" + row + ", " + column + ")")

  def enemiesInRange = for {
    tile <- neighbors(List((-1, 0), (1, 0), (0, -1), (0, 1)))
    if tile.isInstanceOf[Enemy] && tile.asInstanceOf[Enemy].isAlive
  } yield tile.asInstanceOf[Enemy]
  
  def revealTiles {
      val newTiles = newVisibleTiles
      newTiles foreach {_.visible = true}
      player.heal(player.level * newTiles.size)
      enemies foreach { e => e.heal(e.level * newTiles.size) }
  }

  private def newVisibleTiles = for {
    tile <- neighbors(List((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)))
    if !tile.visible
  } yield (tile)

  private def neighbors(directions: List[(Int, Int)]) = for {
    (row, column) <- directions map { t: Tuple2[Int, Int] => (player.row + t._1, player.column + t._2) }
    if isPositionValid(row, column)
  } yield (cells(row)(column))

  private def enemies: Array[Enemy] = for { row <- cells; tile <- row; if tile.isInstanceOf[Enemy] } yield (tile.asInstanceOf[Enemy])
}